home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / database / blt2rx_o.zip / C_SRC.ZIP / CCDOSFN.C < prev    next >
C/C++ Source or Header  |  1996-10-14  |  33KB  |  1,097 lines

  1.  
  2. /*
  3.  *
  4.  * Bullet 2 OS support routines
  5.  * ccdosfn.c - Copyright (C)1996 Cornel Huth
  6.  * 12-Oct-1996 -chh
  7.  *
  8.  */
  9.  
  10. #include <io.h>
  11. #include <fcntl.h>
  12. #include <sys\types.h>
  13. #include <sys\stat.h>
  14. #include <sys\locking.h>
  15. #include <share.h>
  16. #include <direct.h>
  17. #include <errno.h>
  18.  
  19. #include <i86.h>
  20. #include <dos.h>
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <time.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. #include <time.h>
  28. #include <malloc.h>
  29.  
  30. #define LIBENTRY __cdecl
  31.  
  32. #ifndef VOID
  33.  #define VOID void
  34.  #define LONG long
  35.  typedef unsigned long ULONG;
  36.  typedef unsigned char *PSZ;
  37.  typedef const unsigned char *cPSZ;
  38.  typedef VOID *PVOID;
  39. #endif
  40.  
  41. // * For Bullet/X (DOSX32):
  42. // Of the following routines, these four MUST be provided to BULLETX.LIB:
  43. //
  44. // 1. LONG LIBENTRY BulletFree(VOID *baseAddr);
  45. // 2. LONG LIBENTRY BulletMalloc(ULONG bytes, VOID **baseAddrPtr);
  46. // 3. LONG LIBENTRY BulletGetMemoryAvail(void); // __WATCOM__
  47. // 4. LONG LIBENTRY BulletGetTmpDir(char *bufferPtr);
  48. //
  49. // Function pointers to these routines are to be set using SET_VECTORS_XB
  50. // (QSP.item = VECTOR_MALLOC; QSP.itemValue = (ULONG)&BulletMalloc();...)
  51. // If these are not set, when they are called the internal dispatcher returns
  52. // error = 1, function not supported.
  53. //
  54. // * For Bullet/2 and Bullet/95:
  55. // These may be used, or recoded, but they will never be as efficient as
  56. // the internal calls.  See SET_VECTORS_XB for more.
  57. //
  58. // Define FULL_COMPILER_SUPPORT to compile all routines in this module, or
  59. // leave undefined to compile just the four required routines (for DOSX32).
  60. //
  61. // ------------------------------------------------------------------------
  62. //
  63. // Routine protos listed below that end in "// __WATCOM__" include
  64. // compiler-specific code (usually intdos(), or a non-ANSI RTL call)
  65. // and need to be modified for use on other compilers.  In all cases
  66. // where __WATCOM__ is not defined, a suitable default is used, though
  67. // only suitable enough to compile and run.
  68.  
  69. // Watcom compiler flags are non-critical.  Since the code generated here
  70. // is not called often, you may compile with no optimizations without any
  71. // performance loss.  However, the calling convention must be C, with args
  72. // passed on the stack.  Since these are always called by pointer, the name
  73. // doesn't matter (i.e., leading _, or lack of, doesn't matter).  The
  74. // code must be compiled by a 32-bit flat-mode compiler (such as Watcom's
  75. // wcc386 compiler).  A suitable DOS-extender is also required.  Watcom's
  76. // package includes Tenberry's extender, but most any can be used, such as
  77. // Causeway and PMODE.  Borland's PowerPack may work, but it has not been
  78. // tested (Borland's extender is more of a Windows-based extender, rather
  79. // than a DOS-based extender; it is likely that intdos() calls are NOT
  80. // available using Borland's extender support, but with this source, you
  81. // probably will be able to do what is needed to get Bullet/X going just
  82. // fine.)
  83. //
  84. // Any structure packing must be on 1-byte aligns (i.e., no padding).
  85. //
  86. // Actual compile line used in testing (include set to watcom\h):
  87. // wcc386 ccdosfn.c -w4 -e25 -za -s -za -od -of -zl -zld -mf -4s -bt=DOS
  88.  
  89. // This code may be compiled to .obj form and added to the BULLETX.LIB file
  90. // using LIB/WLIB or simply added at LINK time to the final EXE, or it may
  91. // be left in source form and compiled along with the rest of your project.
  92. // Consult your compiler docs on how to build an EXE using an external LIB
  93. // file if you need more details.
  94.  
  95.  
  96.   // -------------------------------- //
  97.   // DOSX32 REQUIRED SUPPORT ROUTINES //
  98.   // -------------------------------- //
  99.  
  100.  
  101. #ifdef __cplusplus
  102.  extern "C" {
  103. #endif
  104.  
  105. LONG LIBENTRY BulletFree(VOID *baseAddr);
  106. LONG LIBENTRY BulletMalloc(ULONG bytes, VOID **baseAddrPtr);
  107. LONG LIBENTRY BulletGetMemoryAvail(void); // __WATCOM__
  108. LONG LIBENTRY BulletGetTmpDir(char *bufferPtr);
  109.  
  110. #ifdef __cplusplus
  111. }
  112. #endif
  113.  
  114. //:FREE MEMORY
  115. // Must be flat (ds=es=ss)
  116.  
  117. LONG LIBENTRY BulletFree(VOID *baseAddr) {
  118.  
  119.  free(baseAddr);
  120.  return 0;
  121.  
  122. }
  123.  
  124. //:ALLOCATE MEMORY
  125. // typical (0-filled required so use calloc)
  126.  
  127. LONG LIBENTRY BulletMalloc(ULONG bytes, VOID **baseAddrPtr) {
  128.  
  129.  *baseAddrPtr = calloc(bytes,1); // checked for NULL internally
  130.  return 0;
  131.  
  132. }
  133.  
  134. //:GET DOS MEMORY (available)
  135. // Watcom-specific compile returns _memmax(), else 128K
  136. // This is a required routine since internally it WOULD depend on
  137. // the BulletMalloc() (which used to be INT21/48/and for this call,
  138. // ebx was set to =1). This is not a critical-need routine in any case.
  139.  
  140. LONG LIBENTRY BulletGetMemoryAvail(void) {
  141.  
  142.  size_t mem;
  143.  
  144. #ifdef __WATCOMC__
  145.  
  146.  mem = _memmax();
  147.  
  148. #else
  149.  
  150.  mem=128*1024;
  151.  
  152. #endif
  153.  
  154.  return (LONG)mem;
  155. }
  156.  
  157.  
  158. //:GET TMP DIR
  159. // typical
  160.  
  161. LONG LIBENTRY BulletGetTmpDir(char *bufferPtr) {
  162.  
  163.  char *ePtr;
  164.  int eLen;
  165.  
  166.  ePtr=getenv("TMP");
  167.  if (ePtr != NULL) {
  168.  
  169.     eLen = strlen(ePtr);
  170.     if ((eLen != 0) && (eLen < 81-8)) {
  171.        strcpy(bufferPtr,ePtr);
  172.     }
  173.     else {
  174.        ePtr=NULL;
  175.     }
  176.  }
  177.  return (LONG)ePtr;   //return NULL (0) if TMP was not found
  178. }
  179.  
  180.  
  181.   //---------------------------------------------------------------//
  182.   //                                                               //
  183.   // The following routines are not required.  They may be used in //
  184.   // whole or in part.  Make them active by using SET_VECTORS_XB.  //
  185.   //                                                               //
  186.   //---------------------------------------------------------------//
  187.  
  188.  
  189. #ifdef FULL_COMPILER_SUPPORT
  190.  
  191. #ifdef __cplusplus
  192.    extern "C" {
  193. #endif
  194.  
  195. //----------------------------------------------------------------------------
  196. //[FILE ROUTINES] ============================================================
  197.  
  198. LONG LIBENTRY BulletCloseFile(ULONG handle);
  199. LONG LIBENTRY BulletCreateDir(cPSZ pathNamePtr);
  200. LONG LIBENTRY BulletCreateFile(cPSZ pathNamePtr);
  201. LONG LIBENTRY BulletDeleteFile(cPSZ pathNamePtr);
  202. LONG LIBENTRY BulletMoveFile(cPSZ orgPathNamePtr, cPSZ newPathNamePtr);
  203. LONG LIBENTRY BulletOpenFile(cPSZ pathNamePtr, LONG openMode, LONG *handlePtr);
  204. LONG LIBENTRY BulletReadFile(LONG handle, LONG *bytesPtr, VOID *bufferPtr);
  205. LONG LIBENTRY BulletSeekFile(LONG handle,LONG seekMode,LONG *offsetPtr);
  206. LONG LIBENTRY BulletUpdateDirEntry(LONG handle);
  207. LONG LIBENTRY BulletWriteFile(LONG handle, LONG *bytesPtr, VOID *bufferPtr);
  208.  
  209. //----------------------------------------------------------------------------
  210. //[NETWORK OS FUNCTIONS] =====================================================
  211.  
  212. LONG LIBENTRY BulletLockFile(LONG handle, LONG lockMode, LONG lockOffset, ULONG lockBytes, ULONG timeout);
  213. LONG LIBENTRY BulletIsDriveRemote(ULONG drive, ULONG *isRemotePtr, ULONG *isSharePtr); // __WATCOM__
  214. LONG LIBENTRY BulletIsFileRemote(ULONG handle, ULONG *isRemotePtr, ULONG *isSharePtr); // __WATCOM__
  215.  
  216. //----------------------------------------------------------------------------
  217. //[GENERAL OS FUNCTIONS] =====================================================
  218.  
  219. LONG LIBENTRY BulletGetSortTable (ULONG codePage, ULONG countryCode, VOID *bufferPtr, ULONG flags);
  220. LONG LIBENTRY BulletGetCountryInfo(ULONG *codePagePtr, ULONG *countryCodePtr, ULONG flags); // __WATCOM__
  221. LONG LIBENTRY BulletGetExtendedError(LONG ecode, ULONG *classPtr, ULONG *actionPtr, ULONG *locusPtr);
  222. LONG LIBENTRY BulletGetVersionDOS(ULONG *verPtr, ULONG *rezPtr, ULONG *maxPathPtr, ULONG *maxCompPtr); // __WATCOM__
  223. LONG LIBENTRY BulletSetHandleCount(ULONG *handlesPtr); // __WATCOM__
  224.  
  225. //----------------------------------------------------------------------------
  226. //[MISC OS FUNCTIONS] ========================================================
  227.  
  228. LONG LIBENTRY BulletGetTimeInfo(ULONG *timePtr, ULONG *datePtr, ULONG *dayPtr, LONG *tzPtr);
  229. LONG LIBENTRY BulletUpperCase(char *strPtr, ULONG strLen);
  230.  
  231. //----------------------------------------------------------------------------
  232. //[SEMAPHORE OS FUNCTIONS]====================================================
  233.  
  234. LONG LIBENTRY BulletCloseMutexSem(ULONG handle);
  235. LONG LIBENTRY BulletCreateMutexSem(ULONG rez1, ULONG *handlePtr, ULONG rez2, ULONG rez3);
  236. LONG LIBENTRY BulletRequestMutexSem(ULONG handle, ULONG timeout);
  237. LONG LIBENTRY BulletReleaseMutexSem(ULONG handle);
  238.  
  239. #ifdef __cplusplus
  240. }
  241. #endif
  242.  
  243.  
  244. //-------------------------------
  245. // Convert CLIB errno to OS error
  246. // finer conversion is possible to non-90xx
  247. // local use
  248.  
  249. int LocalGetErrorCC(void) {
  250.  
  251.  #define bltEZERO     0    /* 0  No error */
  252.  #define bltENOENT    2    /* 1  No such file or directory */
  253.  #define bltE2BIG     9002 /* 2  Arg list too big */
  254.  #define bltENOEXEC   9003 /* 3  Exec format error */
  255.  #define bltEBADF     6    /* 4  Bad file number */
  256.  #define bltENOMEM    8    /* 5  Not enough memory */
  257.  #define bltEACCES    5    /* 6  Permission denied */
  258.  #define bltEEXIST    80   /* 7  File exists */
  259.  #define bltEXDEV     9008 /* 8  Cross-device link */
  260.  #define bltEINVAL    9009 /* 9  Invalid argument */
  261.  #define bltENFILE    9010 /* 10 File table overflow */
  262.  #define bltEMFILE    4    /* 11 Too many open files */
  263.  #define bltENOSPC    39   /* 12 No space left on device */
  264.                            /*    File locking error */
  265.  #define bltEDEADLK   5    /* 15 Resource deadlock would occur */
  266.  #define bltEDEADLOCK 5    /* 15 ... */
  267.  #define bltEINTR     9016 /* 16 interrupt */
  268.  #define bltECHILD    9017 /* 17 Child does not exist */
  269.                            /*    POSIX errors */
  270.  #define bltEAGAIN    9018 /* 18 Resource unavailable, try again */
  271.  #define bltEBUSY     142  /* 19 Device or resource busy */
  272.  #define bltEFBIG     9020 /* 20 File too large */
  273.  #define bltEIO       31   /* 21 I/O error */
  274.  #define bltEISDIR    9022 /* 22 Is a directory */
  275.  #define bltENOTDIR   9023 /* 23 Not a directory */
  276.  #define bltEMLINK    9024 /* 24 Too many links */
  277.  #define bltENOTBLK   9025 /* 25 Block device required */
  278.  #define bltENOTTY    9026 /* 26 Not a character device */
  279.  #define bltENXIO     9027 /* 27 No such device or address */
  280.  #define bltEPERM     9028 /* 28 Not owner */
  281.  #define bltEPIPE     9029 /* 29 Broken pipe */
  282.  #define bltEROFS     5    /* 30 Read-only file system */
  283.  #define bltESPIPE    9031 /* 31 Illegal seek */
  284.  #define bltESRCH     9032 /* 32 No such process */
  285.  #define bltETXTBSY   9033 /* 33 Text file busy */
  286.  #define bltEFAULT    9034 /* 34 Bad address */
  287.  #define bltENAMETOOLONG  9035 /* 35 Name too long */
  288.  #define bltENODEV    9036 /* 36 No such device */
  289.  #define bltENOLCK    9037 /* 37 No locks available in system */
  290.  #define bltENOSYS    1    /* 38 Unknown system call */
  291.  #define bltENOTEMPTY 9039 /* 39 Directory not empty */
  292.  
  293.  int rez;
  294.  
  295.  rez=errno;
  296.  switch (rez) {
  297.   case EZERO        : rez=bltEZERO       ;break;
  298.   case ENOENT       : rez=bltENOENT      ;break;
  299.   case E2BIG        : rez=bltE2BIG       ;break;
  300.   case ENOEXEC      : rez=bltENOEXEC     ;break;
  301.   case EBADF        : rez=bltEBADF       ;break;
  302.   case ENOMEM       : rez=bltENOMEM      ;break;
  303.   case EACCES       : rez=bltEACCES      ;break;
  304.   case EEXIST       : rez=bltEEXIST      ;break;
  305.   case EXDEV        : rez=bltEXDEV       ;break;
  306.   case EINVAL       : rez=bltEINVAL      ;break;
  307.   case ENFILE       : rez=bltENFILE      ;break;
  308.   case EMFILE       : rez=bltEMFILE      ;break;
  309.   case ENOSPC       : rez=bltENOSPC      ;break;
  310.   //case EDEADLK      : rez=bltEDEADLK     ;break; // same as EDEADLOCK
  311.   case EDEADLOCK    : rez=bltEDEADLOCK   ;break;
  312.   case EINTR        : rez=bltEINTR       ;break;
  313.   case ECHILD       : rez=bltECHILD      ;break;
  314.  
  315.   case EAGAIN       : rez=bltEAGAIN      ;break;
  316.   case EBUSY        : rez=bltEBUSY       ;break;
  317.   case EFBIG        : rez=bltEFBIG       ;break;
  318.   case EIO          : rez=bltEIO         ;break;
  319.   case EISDIR       : rez=bltEISDIR      ;break;
  320.   case ENOTDIR      : rez=bltENOTDIR     ;break;
  321.   case EMLINK       : rez=bltEMLINK      ;break;
  322.   case ENOTBLK      : rez=bltENOTBLK     ;break;
  323.   case ENOTTY       : rez=bltENOTTY      ;break;
  324.   case ENXIO        : rez=bltENXIO       ;break;
  325.   case EPERM        : rez=bltEPERM       ;break;
  326.   case EPIPE        : rez=bltEPIPE       ;break;
  327.   case EROFS        : rez=bltEROFS       ;break;
  328.   case ESPIPE       : rez=bltESPIPE      ;break;
  329.   case ESRCH        : rez=bltESRCH       ;break;
  330.   case ETXTBSY      : rez=bltETXTBSY     ;break;
  331.   case EFAULT       : rez=bltEFAULT      ;break;
  332.   case ENAMETOOLONG : rez=bltENAMETOOLONG;break;
  333.   case ENODEV       : rez=bltENODEV      ;break;
  334.   case ENOLCK       : rez=bltENOLCK      ;break;
  335.   case ENOSYS       : rez=bltENOSYS      ;break;
  336.   case ENOTEMPTY    : rez=bltENOTEMPTY   ;break;
  337.   default: rez=9099;
  338.  }
  339.  return rez;
  340. }
  341.  
  342.  
  343.  
  344.  
  345. //----------------------------------------------------------------------------
  346. //[FILE ROUTINES] ============================================================
  347.  
  348. //:CLOSE FILE
  349. // typical
  350.  
  351. LONG LIBENTRY BulletCloseFile(ULONG handle) {
  352.  
  353.  int rez;
  354.  
  355.  rez = close((int)handle);
  356.  if (rez== -1) rez=LocalGetErrorCC();
  357.  return (LONG)rez;
  358. }
  359.  
  360.  
  361. //:CREATE DIRECTORY
  362. // typical
  363.  
  364. LONG LIBENTRY BulletCreateDir(cPSZ pathNamePtr) {
  365.  
  366.  int rez;
  367.  
  368.  rez = mkdir(pathNamePtr);
  369.  if (rez== -1) rez=LocalGetErrorCC();
  370.  return (LONG)rez;
  371. }
  372.  
  373.  
  374. //:CREATE FILE
  375. // typical
  376.  
  377. LONG LIBENTRY BulletCreateFile(cPSZ pathNamePtr) {
  378.  
  379.  int rez;
  380.  int handle;
  381.  
  382.  handle = sopen(pathNamePtr,
  383.                 O_CREAT | O_EXCL | O_RDWR | O_BINARY,
  384.                 SH_DENYRW,
  385.                 S_IREAD | S_IWRITE);
  386.  if (handle== -1) {
  387.     rez=LocalGetErrorCC();
  388.  }
  389.  else {
  390.     close(handle);   // only create it, so close after a good create
  391.     rez=0;
  392.  }
  393.  return (LONG)rez;
  394. }
  395.  
  396.  
  397. //:DELETE FILE
  398. // typical
  399.  
  400. LONG LIBENTRY BulletDeleteFile(cPSZ pathNamePtr) {
  401.  
  402.  int rez;
  403.  
  404.  rez = remove(pathNamePtr);
  405.  if (rez== -1) rez=LocalGetErrorCC();
  406.  return (LONG)rez;
  407. }
  408.  
  409.  
  410. //:RENAME (Move) FILE
  411. // typical
  412.  
  413. LONG LIBENTRY BulletMoveFile(cPSZ orgPathNamePtr, cPSZ newPathNamePtr) {
  414.  
  415.  int rez;
  416.  
  417.  rez = rename(orgPathNamePtr, newPathNamePtr);
  418.  if (rez== -1) rez=LocalGetErrorCC();
  419.  return (LONG)rez;
  420. }
  421.  
  422.  
  423. //:OPEN FILE
  424. // if handle <=2 is returned to Bullet, Bullet will leave the handle
  425. // alone and issue ERR_SYSTEM_HANDLE (8305) returned for rez.  Your
  426. // app level code (OPEN_DATA_XB, etc.) should reissue the open request.
  427.  
  428. LONG LIBENTRY BulletOpenFile(cPSZ pathNamePtr, LONG openMode, LONG *handlePtr) {
  429.  
  430.  int rez;
  431.  int handle;
  432.  int oflag, shflag;
  433.  
  434.  *(handlePtr)=0;
  435.  
  436.  switch (openMode & 0x03) {
  437.   case 0: oflag = O_RDONLY | O_BINARY; break;
  438.   case 1: oflag = O_WRONLY | O_BINARY; break;
  439.   default:oflag = O_RDWR   | O_BINARY; break;
  440.  }
  441.  
  442.  switch (openMode & 0x70) {             // no-inherit is not supported by sopen()
  443.   case 0x10: shflag = SH_DENYRW; break; // deny read-write
  444.   case 0x20: shflag = SH_DENYWR; break; // deny write
  445.   case 0x30: shflag = SH_DENYRD; break; // deny read
  446.   case 0x40: shflag = SH_DENYNO; break; // deny none
  447.   default: shflag = SH_DENYNO;   break; // SH_COMPAT is not a good idea so deny none when case==0
  448.  }
  449.  
  450.  handle = sopen(pathNamePtr, oflag, shflag);
  451.  if (handle== -1) {
  452.     rez=LocalGetErrorCC();
  453.  }
  454.  else {
  455.     *(handlePtr)=(LONG)handle;
  456.     rez=0;
  457.  }
  458.  return (LONG)rez;
  459. }
  460.  
  461.  
  462. //:READ FILE
  463. // extender typically handles requests for >64K bytes  --if not, shrink
  464. // Bullet pack/reindex buffers so that no single read request is larger than
  465. // 65520 bytes (or 32767 for some C RTLs)
  466. //
  467. // if bytesRead is not the same as bytes-requested this routine does
  468. // NOT return an error (simply return the bytes actually read)
  469.  
  470. LONG LIBENTRY BulletReadFile(LONG handle, LONG *bytesPtr, VOID *bufferPtr) {
  471.  
  472.  int rez;
  473.  int bytesRead;
  474.  
  475.  bytesRead = read((int)handle, bufferPtr, (unsigned int) *(bytesPtr));
  476.  if (bytesRead== -1) {
  477.     rez=LocalGetErrorCC();
  478.  }
  479.  else {
  480.     *(bytesPtr)=(LONG)bytesRead;
  481.     rez=0;
  482.  }
  483.  return (LONG)rez;
  484. }
  485.  
  486.  
  487. //:SEEK TO FILE POSITION
  488. // typical
  489.  
  490. LONG LIBENTRY BulletSeekFile(LONG handle,LONG seekMode,LONG *offsetPtr) {
  491.  
  492.  int rez;
  493.  long currPos;
  494.  
  495.  currPos = lseek((int)handle, *(offsetPtr), (int)seekMode);
  496.  if (currPos== -1) {
  497.     rez=LocalGetErrorCC();
  498.  }
  499.  else {
  500.     *(offsetPtr)=currPos;
  501.     rez=0;
  502.  }
  503.  return (LONG)rez;
  504. }
  505.  
  506.  
  507. //:UPDATE DIR ENTRY
  508. // typical
  509.  
  510. LONG LIBENTRY BulletUpdateDirEntry(LONG handle) {
  511.  
  512.  int rez;
  513.  int handleCommit;
  514.  
  515.  handleCommit=dup(handle);
  516.  if (handleCommit== -1) {
  517.     rez=LocalGetErrorCC();
  518.  }
  519.  else {
  520.     close(handleCommit);
  521.     rez=0;
  522.  }
  523.  return (LONG)rez;
  524. }
  525.  
  526.  
  527. //:WRITE FILE
  528. // extender typically handles requests for >64K bytes  --if not, shrink
  529. // Bullet pack/reindex buffers so that no single read request is larger than
  530. // 65520 bytes (or 32767 for some C RTLs)
  531. //
  532. // if bytesWritten is not the same as bytes-requested this routine does
  533. // NOT return an error (simply return the bytes actually written)
  534. // (a ERR_DISK_FULL is generated internally by Bullet if this is the case)
  535. //
  536. // If *bytesPtr=0 (write 0 bytes) file is to be truncated at its current
  537. // position.  In DOS, this is the case (i.e., the OS does this when bytes-to-write
  538. // is 0).  chsize() may be an alternate option when 0.
  539.  
  540. LONG LIBENTRY BulletWriteFile(LONG handle, LONG *bytesPtr, VOID *bufferPtr) {
  541.  
  542.  int rez;
  543.  int bytesWritten;
  544.  
  545.  bytesWritten = write((int)handle, bufferPtr, (unsigned int) *(bytesPtr));
  546.  if (bytesWritten== -1) {
  547.     rez=LocalGetErrorCC();
  548.  }
  549.  else {
  550.     *(bytesPtr)=(LONG)bytesWritten;
  551.     rez=0;
  552.  }
  553.  return (LONG)rez;
  554. }
  555.  
  556.  
  557.  
  558.  
  559. //----------------------------------------------------------------------------
  560. //[NETWORK OS FUNCTIONS] =====================================================
  561.  
  562. //:LOCK/UNLOCK FILE
  563. // lockMode: bit0=0 lock
  564. //           bit0=1 unlock
  565. //    n/a    bit1=0 exclusive access to locked region by process (R/W)
  566. //    n/a    bit1=1 read access to locked region, but not write for any
  567. //    n/a    bit2=1 atomic lock operation (unlock then lock, for relock only)
  568. //    n/a = not available in DOSX32
  569.  
  570. LONG LIBENTRY BulletLockFile(LONG handle, LONG lockMode, LONG lockOffset, ULONG lockBytes, ULONG timeout) {
  571.  
  572.  int rez, rez2;
  573.  int lockType;
  574.  
  575.  LONG currPos=0;
  576.  LONG newPos;
  577.  
  578.  if ((lockMode & 1)==1) {
  579.     lockType=LK_UNLCK;     // unlock if bit0=1
  580.  }
  581.  else {
  582.     lockType=LK_NBLCK;     // lock if bit0=1 (non-blocking, or use timeout as basis to block)
  583.  }
  584.  
  585.  // locking() used over lock() since more likely supported by the RTL
  586.  
  587.  rez = BulletSeekFile(handle,1,&currPos);
  588.  if (rez==0) {
  589.  
  590.     newPos = lockOffset;
  591.     rez = BulletSeekFile(handle,0,&newPos);
  592.     if (rez==0) {
  593.        rez = locking(handle,lockType,lockBytes);
  594.        if (rez==-1) rez=LocalGetErrorCC();
  595.     }
  596.  
  597.     //even though Bullet file operations are atomic, the position is restored
  598.     rez2 = BulletSeekFile(handle,0,&currPos); // restore position
  599.  
  600.     if (rez==0) rez=rez2;
  601.  }
  602.  return (LONG)rez;
  603.  
  604.  timeout;  // ref it-unreachable-use it if you can
  605. }
  606.  
  607.  
  608. //:QUERY DRIVE REMOTE
  609. // used for informational use only (non-critical)
  610. // Requires making INT call if not otherwise supported by a compiler call.
  611. // The source below compiles with a Watcom compiler (10a, for example), if not:
  612. //
  613. // This code sets remote and share flags to 1, indicating that the file
  614. // is remote and that SHARE.EXE (or compatible) is installed.  The purpose
  615. // is information, and is used to determine whether locking is required.
  616. // Since it's better to lock and not need to than to not lock and need to,
  617. // this code returns 1 in both cases.  If SHARE is not installed, a run-time
  618. // error is returned by BulletLockFile(), above (try it).  This may also
  619. // happen if run in a Windows DOS box since Windows always reports that
  620. // SHARE is installed (it should be if it isn't).
  621.  
  622. LONG LIBENTRY BulletIsDriveRemote(ULONG drive, ULONG *isRemotePtr, ULONG *isSharePtr) {
  623.  
  624.  int rez;
  625.  
  626. #ifdef __WATCOMC__
  627.  
  628.  union REGS iregs, oregs;
  629.  
  630.  *(isRemotePtr)=1;
  631.  *(isSharePtr)=1;
  632.  
  633.  iregs.x.eax = 0x4409;
  634.  iregs.x.ebx = drive;   // 0=current/default, 1=A:, 2=B:, 3=C:...
  635.  iregs.x.edx = 0;
  636.  rez = intdos(&iregs, &oregs);
  637.  if ((oregs.x.cflag & 1)==0) {
  638.     if ((oregs.x.edx & (1 << 12))==1) *(isRemotePtr)=1;  // bit12=1 then remote
  639.     rez = 0;
  640.  }
  641.  
  642.  oregs.x.eax = -1;      // init to non-zero for 0-compare after call
  643.  iregs.x.eax = 0x1000;  // ignore error since not likely, and it won't matter
  644.  int386(0x2F, &iregs, &oregs);
  645.  if ((oregs.h.al)==0) {  // installed only if al=FF
  646.     *(isSharePtr)=0;
  647.  }
  648.  
  649. #else
  650.  
  651.  *(isRemotePtr)=1;
  652.  *(isSharePtr)=1;
  653.  rez=0;
  654.  
  655. #endif
  656.  
  657.  return (LONG)rez;
  658. }
  659.  
  660.  
  661. //:QUERY FILE REMOTE
  662. // see notes for QUERY DRIVE REMOTE
  663.  
  664. LONG LIBENTRY BulletIsFileRemote(ULONG handle, ULONG *isRemotePtr, ULONG *isSharePtr) {
  665.  
  666.  int rez;
  667.  
  668. #ifdef __WATCOMC__
  669.  
  670.  union REGS iregs, oregs;
  671.  
  672.  *(isRemotePtr)=1;
  673.  *(isSharePtr)=1;
  674.  
  675.  iregs.x.eax = 0x440A;
  676.  iregs.x.ebx = handle;
  677.  iregs.x.edx = 0;
  678.  rez = intdos(&iregs, &oregs);
  679.  if ((oregs.x.cflag & 1)==0) {
  680.     if ((oregs.x.edx & (1 << 15))==1) *(isRemotePtr)=1;  // bit15=1 then remote
  681.     rez = 0;
  682.  }
  683.  
  684.  oregs.x.eax = -1;      // init to non-zero for 0-compare after call
  685.  iregs.x.eax = 0x1000;  // ignore error since not likely, and it won't matter
  686.  int386(0x2F, &iregs, &oregs);
  687.  if ((oregs.h.al)==0) {  // installed only if al=FF
  688.     *(isSharePtr)=0;
  689.  }
  690.  
  691. #else
  692.  
  693.  *(isRemotePtr)=1;
  694.  *(isSharePtr)=1;
  695.  rez=0;
  696.  
  697. #endif
  698.  
  699.  return (LONG)rez;
  700. }
  701.  
  702.  
  703.  
  704.  
  705. //----------------------------------------------------------------------------
  706. //[GENERAL OS FUNCTIONS] =====================================================
  707.  
  708.  
  709.  
  710. //:GET COLLATE SEQUENCE
  711. //default is for US codePage
  712.  
  713. LONG LIBENTRY BulletGetSortTable (ULONG codePage, ULONG countryCode, VOID *bufferPtr, ULONG flags) {
  714.  
  715.  // OEM cp=437 table along MS-DOS, OS/2 lines (similar to Windows OEM)
  716.  
  717.  static char sortTableOEM[] = {
  718. 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
  719. 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
  720. 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
  721. 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
  722. 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  723. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
  724. 0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  725. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x7F,
  726. 0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41,
  727. 0x45,0x41,0x41,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x24,0x24,0x24,0x24,0x24,
  728. 0x41,0x49,0x4F,0x55,0x4E,0x4E,0xA6,0xA7,0x3F,0xA9,0xAA,0xAB,0xAC,0x21,0x22,0x22,
  729. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
  730. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  731. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
  732. 0xE0,0x53,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
  733. 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
  734. };
  735.  
  736.  // ANSI cp=1252 table along Windows lines
  737.  
  738.  static char sortTableANSI[] = {
  739. 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
  740. 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
  741. 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
  742. 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
  743. 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  744. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
  745. 0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  746. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x7F,
  747. 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  748. 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F,
  749. 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
  750. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
  751. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  752. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
  753. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  754. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F
  755. };
  756.  
  757.  if (flags & 1) {
  758.  
  759.     // USE_ANSI_SET flag in CREATE_INDEX_XB
  760.  
  761.     memmove(bufferPtr,sortTableANSI,256);
  762.  }
  763.  else {
  764.     memmove(bufferPtr,sortTableOEM,256);
  765.  }
  766.  return 0;
  767.  
  768.  codePage;
  769.  countryCode;
  770.  flags;
  771.  
  772. #if 0
  773.  
  774.  // --------------------------------------------------------------------------
  775.  // the original assembly is shown for reference if you want
  776.  // to do inline assembly to get the DOS table -- results
  777.  // may be less than perfect (DOS may return an invalid table)
  778.  // NOTE that this is the  DOSX32  original version
  779.  // and both
  780.  
  781. ;--------------------
  782. ;GET COLLATE SEQUENCE
  783. ; in: ecx=code page ID
  784. ;     edx=country code
  785. ;     edi->buffer to store sequence table (256 bytes)
  786. ;     esi=OEM (0) or ANSI (1) flag (for Windows use only, selects char set)
  787. ;out: eax=0, or error if CF=1
  788. ;use:
  789. ;nts: uses DPMI call to ax=6 verify selector!
  790. ;     if ERR_216506 returned, instruct user to provide own collate table
  791. ;DOS4GW does return 6,seg:off, but only a 16-bit offset! (06,ofs16,selector)
  792.  
  793. PROC
  794.  LOCAL \
  795.  sBuffer[20]:DWORD
  796.  
  797.  mov     ebx,ecx         ;ebx=cp / edx=cc
  798.  mov     ecx,5           ;get 5 bytes worth
  799.  mov     ax,6506h        ;es:edi->buffer (use dest buffer for a sec)
  800.  int 21h
  801.  jc      ExitNotSupported
  802.  cmp     BPTR [edi],6    ;valid identifier?
  803.  jne     ExitNotSupported ;no!
  804.  
  805.  movzx   esi,WPTR [edi+1];16-bit offset so movzx
  806.  mov     bx,WPTR [edi+3] ;and selector to bx for testing
  807.  
  808.  mov     ax,6            ;DPMI Get Segment Base Address
  809.  int 31h                 ;used only to validate selector
  810.  jc      ExitNotSupported
  811.  
  812.  push    ds              ;(save ds)
  813.  mov     ds,bx           ;ds:esi->table size word
  814.  movzx   ecx,WPTR [esi]  ;get size in bytes
  815.  cmp     ecx,256         ;valid size?
  816.  jne     ExitNS2         ;no
  817.  add     esi,2
  818.  shr     ecx,2           ;move dwords at a time (256/4=64 dwords)
  819.  rep movsd
  820.  pop     ds              ;(back ds)
  821.  sub     eax,eax
  822. ExitGen:
  823.  ret
  824.  
  825. ExitNotSupported:
  826.  mov     eax,ERR_216506 ;(ERR_216506 = 8256)
  827.  stc
  828.  jmp     ExitGen
  829. ExitNS2:
  830.  pop     ds              ;(back ds)
  831.  jmp     ExitNotSupported
  832. ENDP
  833.  
  834.   // -------------------------------------------------------------------------
  835.  
  836. #endif
  837. }
  838.  
  839.  
  840. //:GET COUNTRY INFO
  841. // requires WATCOM-specific intdos() support, else returns parms same as args
  842.  
  843. LONG LIBENTRY BulletGetCountryInfo(ULONG *codePagePtr, ULONG *countryCodePtr, ULONG flags) {
  844.  
  845.  int rez;
  846.  ULONG cc, cp;
  847.  
  848. #ifdef __WATCOMC__
  849.  
  850.  char buffer[44];
  851.  unsigned short *tmpPtr;
  852.  
  853.  union REGS iregs, oregs;
  854.  
  855.  iregs.x.eax = 0x6501;
  856.  iregs.x.ecx = 40;
  857.  iregs.x.edi = (ULONG)(&buffer)+3;  // for alignment
  858.  rez = intdos(&iregs, &oregs);
  859.  if ((oregs.x.cflag & 1)==0) {
  860.  
  861.     tmpPtr = (unsigned short*) &buffer[3];
  862.     cc = *(tmpPtr);
  863.     cp = *(++tmpPtr);
  864.  }
  865.  else {
  866.     rez = 8251;   // Bullet ERR_216501 (extender support lacking)
  867.  }
  868.  
  869. #else
  870.  
  871.     // one way to do it (easier to change this way since common exit assigns done)
  872.  
  873.     cc = *countryCodePtr;
  874.     cp = *codePagePtr;
  875.     rez=0;
  876.  
  877. #endif
  878.  
  879.  if (*countryCodePtr==0) *countryCodePtr = cc;
  880.  if (*codePagePtr==0) *codePagePtr = cp;
  881.  return (LONG)rez;
  882.  
  883.  flags;
  884. }
  885.  
  886.  
  887. //:GET EXTENDED ERROR
  888. // for informational use; not supported so returned *Ptr==0
  889.  
  890. LONG LIBENTRY BulletGetExtendedError(LONG ecode, ULONG *classPtr, ULONG *actionPtr, ULONG *locusPtr) {
  891.  
  892.  *classPtr=0;
  893.  *actionPtr=0;
  894.  *locusPtr=0;
  895.  return 0;
  896.  
  897.  ecode;
  898. }
  899.  
  900.  
  901. //:GET DOS VERSION
  902. // Watcom-specific compile uses intdos(), else returns version 500 (for DOS 5.0)
  903.  
  904. LONG LIBENTRY BulletGetVersionDOS(ULONG *verPtr, ULONG *rezPtr, ULONG *maxPathPtr, ULONG *maxCompPtr) {
  905.  
  906.  int rez;
  907.  
  908. #ifdef __WATCOMC__
  909.  
  910.  union REGS iregs, oregs;
  911.  
  912.  iregs.x.eax = 0x3000;
  913.  rez = intdos(&iregs, &oregs);
  914.  *verPtr = (iregs.h.al * 100) + (iregs.h.ah);
  915.  
  916. #else
  917.  
  918.  *verPtr = 500;   // assume DOS 5.0
  919.  rez = 0;
  920.  
  921. #endif
  922.  
  923.  strncpy((char *)rezPtr,"2TLB",4);
  924.  *maxPathPtr = 81;
  925.  *maxCompPtr = 8; // preferred over 11
  926.  return (LONG)rez;
  927. }
  928.  
  929.  
  930.  
  931.  
  932. //:SET HANDLE COUNT
  933. // Watcom-specific compile uses intdos(), else no action (max 15 handles then)
  934. //
  935. // *handlesPtr is to return the max number of handles available
  936. // if *handlesPtr==0 on entry, return max number of handles available
  937. // in DOS, this is not a supported service, so tracked internally
  938. // (i.e., leave value in *handlesPtr as is)
  939. //
  940. // Note: Even though Watcom's _grow_handle() does return the max
  941. // handles that can be open (with restrictions), it returns 256
  942. // when 255 is used as its arg.  DOS nevers uses handle FF since
  943. // this is reserved for the 'unused' slot marker in the file
  944. // tables, so the max possible is 255 (numbered 0-254).  A safe
  945. // bet here is to let Bullet handles this case, and just leave
  946. // *handlesPtr as-is.
  947.  
  948. LONG LIBENTRY BulletSetHandleCount(ULONG *handlesPtr) {
  949.  
  950.  int rez;
  951.  
  952. #ifdef __WATCOMC__
  953.  
  954.  // The Watcom RTL 'open' support requires that _grow_handles()
  955.  // be used; simply using DOS INT21/67 is not sufficient, even
  956.  // though the open support routines used DOS handles directly
  957.  // (this may be related to the extender)
  958.  //
  959.  //union REGS iregs, oregs;
  960.  //
  961.  //iregs.x.eax = 0x6700;
  962.  //iregs.x.ebx = *handlesPtr;
  963.  //rez = intdos(&iregs, &oregs);
  964.  //if ((oregs.x.cflag & 1)==0) rez=0;
  965.  
  966.  rez = _grow_handles((int)*handlesPtr);
  967.  if (rez== -1) {
  968.     rez=LocalGetErrorCC();
  969.  }
  970.  else {
  971.     rez=0;
  972.  }
  973.  
  974. #else
  975.  
  976.  // you won't be able to open more than 15 or so handles concurrently
  977.  // unless this is coded for your compiler -- also be sure to increase
  978.  // FILES= in config.sys (set to no more than FILES=255)
  979.  
  980.  rez=0;
  981.  
  982. #endif
  983.  
  984.  return (LONG)rez;
  985. }
  986.  
  987.  
  988.  
  989.  
  990. //----------------------------------------------------------------------------
  991. //[MISC OS FUNCTIONS] ========================================================
  992.  
  993. //:GET DATE/TIME
  994. // typical
  995.  
  996. LONG LIBENTRY BulletGetTimeInfo(ULONG *timePtr, ULONG *datePtr, ULONG *dayPtr, LONG *tzPtr) {
  997.  
  998.  #define daTZ  0xFF00
  999.  
  1000.  struct tm *daTime;
  1001.  time_t daTicks;
  1002.  
  1003.  static int huns = 99;
  1004.  
  1005.  // hundreths are needed so simulate
  1006.  
  1007.  huns++;
  1008.  if (huns==100) huns=0;
  1009.  
  1010.  time(&daTicks);
  1011.  daTime = localtime(&daTicks);
  1012.  
  1013.  *(timePtr) = (daTime->tm_hour) + (daTime->tm_min << 8) + (daTime->tm_sec << 16) + (huns << 24);
  1014.  *(datePtr) = (daTime->tm_year +1900) + ((daTime->tm_mon+1) << 16) + (daTime->tm_mday << 24);
  1015.  *(dayPtr)  = (daTime->tm_wday);
  1016.  *(tzPtr)   = (LONG) daTZ;
  1017.  
  1018.  return 0;
  1019. }
  1020.  
  1021.  
  1022. //:UPPERCASE STRING
  1023. // Used to upper-case fieldnames, key expression, and value in UPPER().
  1024. // This likely will not work for char > 127, but this should not pose
  1025. // a problem since field names (and hence, key expression and UPPER()
  1026. // value) should be standard ASCII only.
  1027. // Filenames do NOT have their case changed (that's FILE names).
  1028. // String likely is NOT 0-terminated,
  1029. // String will NOT contain embedded 0s.
  1030.  
  1031. LONG LIBENTRY BulletUpperCase(char *strPtr, ULONG strLen) {
  1032.  
  1033.  while (strLen--) {
  1034.     toupper(*strPtr++);
  1035.  }
  1036.  
  1037.  return 0;
  1038. }
  1039.  
  1040.  
  1041.  
  1042.  
  1043. //----------------------------------------------------------------------------
  1044. //[SEMAPHORE OS FUNCTIONS]====================================================
  1045.  
  1046. //:CLOSE MUTEX SEMAPHORE
  1047. // used at EXIT_XB
  1048.  
  1049. LONG LIBENTRY BulletCloseMutexSem(ULONG handle) {
  1050.  
  1051.  return 0;
  1052.  
  1053.  handle;
  1054. }
  1055.  
  1056.  
  1057. //:CREATE MUTEX SEMAPHORE
  1058. // used at first Bullet call
  1059.  
  1060. LONG LIBENTRY BulletCreateMutexSem(ULONG rez1, ULONG *handlePtr, ULONG rez2, ULONG rez3) {
  1061.  
  1062.  *handlePtr=1;  // return non-zero to prevent later calls
  1063.  return 0;
  1064.  
  1065.  rez1;   // passed=0, unnamed semaphore
  1066.  rez2;   // passed=0, not shared with other processes
  1067.  rez3;   // passed=0, initiallly unowned semaphore
  1068.  handlePtr;
  1069. }
  1070.  
  1071.  
  1072. //:REQUEST MUTEX SEMAPHORE
  1073. // used at each Bullet call
  1074.  
  1075. LONG LIBENTRY BulletRequestMutexSem(ULONG handle, ULONG timeout) {
  1076.  
  1077.  return 0;
  1078.  
  1079.  handle;
  1080.  timeout;   // passed=as set by sysvar
  1081. }
  1082.  
  1083.  
  1084. //:RELEASE MUTEX SEMAPHORE
  1085. // used at each Bullet call
  1086.  
  1087. LONG LIBENTRY BulletReleaseMutexSem(ULONG handle) {
  1088.  
  1089.  return 0;
  1090.  
  1091.  handle;
  1092. }
  1093.  
  1094. #endif // #ifdef FULL_COMPILER_SUPPORT
  1095.  
  1096. // <EOF>
  1097.